package modules.traitements;

import gnu.prolog.database.Pair;
//import gnu.prolog.demo.mentalarithmetic.NoAnswerException;
import gnu.prolog.database.PrologTextLoaderError;
import gnu.prolog.io.ParseException;
import gnu.prolog.io.TermReader;
import gnu.prolog.io.TermWriter;
import gnu.prolog.term.AtomTerm;
import gnu.prolog.term.AtomicTerm;
import gnu.prolog.term.CompoundTerm;
import gnu.prolog.term.IntegerTerm;
import gnu.prolog.term.Term;
import gnu.prolog.term.VariableTerm;
import gnu.prolog.vm.Environment;
import gnu.prolog.vm.Interpreter;
import gnu.prolog.vm.Interpreter.Goal;
import gnu.prolog.vm.PrologCode;
import gnu.prolog.vm.PrologException;
import gnu.prolog.vm.TermConstants;

import java.awt.DisplayMode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import javax.management.monitor.Monitor;

import core.Mesure;

public class Breaks {

	
	private static class NoAnswerException extends Exception
	{
	    private static final long serialVersionUID = 2808738995798796114L;

	    /**
	     * @param message
	     */
	    public NoAnswerException(String message)
	    {
	        super(message);
	    }

	}
	
	
	
	private Breaks()
	{}

	/**
	 * @see #main(String[])
	 */
	private static final int DEFAULTLIMIT = 500;
	/**
	 * @see #main(String[])
	 */
	private static final int DEFAULTLENGTH = 5;
	/**
	 * The USAGE of this program as a standalone program.
	 */
	public static final String USAGE = "Either no arguments or {Limit, Length}.\n"
			+ " Where Limit is the largest number to use and Length is the number of " + "operations to use.\n"
			+ "--help|-h displays this usage text.";

	/**
	 * Whether we have done {@link #setup()} or not.
	 */
	private static boolean issetup = false;

	/**
	 * The {@link Environment} we are using.
	 * 
	 * @see #setup() for creation
	 * @see #generateQuestion(int,int) for usage
	 */
	private static Environment env;
	/**
	 * The {@link Interpreter} we are using.
	 * 
	 * @see #setup() for creation
	 * @see #generateQuestion(int,int) for usage
	 */
	private static Interpreter interpreter;
	
	/**
	 * Ensure that we have an environment and have loaded the prolog code and have
	 * an interpreter to use.
	 */
	private synchronized static void setup()
	{
		if (issetup)
		{
			return;// don't setup more than once
		}

		// Construct the environment
		env = new Environment();

		// get the filename relative to the class file
		env.ensureLoaded(AtomTerm.get("break.pl"));

		// Get the interpreter.
		interpreter = env.createInterpreter();
		// Run the initialization
		env.runInitialization(interpreter);

		// So that we don't repeat ourselves
		issetup = true;
	}

	/**
	 * Collect debugging information if something has gone wrong in particular get
	 * any {@link PrologTextLoaderError PrologTextLoaderErrors} which were created
	 * during loading.
	 */
	private static void debug()
	{
		List<PrologTextLoaderError> errors = env.getLoadingErrors();
		for (PrologTextLoaderError error : errors)
		{
			error.printStackTrace();
		}

		/*
		 * Map<AtomTerm, Term> atom2flag = env.getPrologFlags(); Set<AtomTerm> atoms
		 * = atom2flag.keySet(); for (AtomTerm a : atoms) {
		 * System.out.println(a.toString() + " => " + atom2flag.get(a)); }
		 */
		}

	public static String generateBreak( int nbBreaks,
			ArrayList<String> contenuDuBreak) {
		setup();
		
		// Create variable terms so that we can pull the answers out later
		//VariableTerm listTerm = new VariableTerm("List");
		VariableTerm answerTerm = new VariableTerm("Answer");
		
		Term contenuDuBreakTerm = miseEnFormeBreak(contenuDuBreak);
		
		String enTete = "-- Declarations\n"+
					"-- Chart\n";
		String mesureType = "\n.mesure \n\n:hh |x-x-x-x-x-x-x-x-|\n"+
		":sn |----o-------o---|\n"+
		":ba |o-------o-------|\n";
		
		
		
		
		// Create the arguments to the compound term which is the question
		Term[] args = {contenuDuBreakTerm, answerTerm };
		// Construct the question
		CompoundTerm goalTerm = new CompoundTerm(AtomTerm.get("genererBreak"), args);

		synchronized (interpreter)// so that this class is thread safe.
		{
			// Print out any errors
			debug();
			// Execute the goal and return the return code.
			int rc = 0;
			int numeroDuBreak = 1;
			String breakPossibles =""; 
			try {
				//rc = interpreter.runOnce(goalTerm);
				Goal myGoal = interpreter.prepareGoal(goalTerm);

				for (int k = 0; k < nbBreaks; k++) {
					int lower = 500;
					int higher = 2000;

					int random = (int)(Math.random() * (higher-lower)) + lower;
					for (int l = 0; l < random; l++) {
						rc = interpreter.execute(myGoal);
					}
					// If it succeeded.
	
					if (rc == PrologCode.SUCCESS || rc == PrologCode.SUCCESS_LAST)
					{
						breakPossibles += mesureType+"\n.BREAK "+numeroDuBreak+"\n\n"+
						":hh |----x-------x---|\n"+
						":ba |o-------o-------|\n";
						Term valeur = answerTerm.dereference();
						Term[] listeDesValeurs = ((CompoundTerm)valeur).args;
				
						HashMap<String, String> symboleNotes = new HashMap<String, String>();
						
						for (int i = 0; i < contenuDuBreak.size(); i++) {
							//System.out.println(contenuDuBreak.get(i)+ listeDesValeurs[0].toString());
							symboleNotes.put(contenuDuBreak.get(i), listeDesValeurs[0].toString());
							if(listeDesValeurs[1].dereference().getTermType() !=  Term.ATOM) listeDesValeurs = ((CompoundTerm)listeDesValeurs[1].dereference()).args;
						}
						for(Entry<String, String> entry : symboleNotes.entrySet()) {
						    String symbole = entry.getKey();
						    String notes = entry.getValue();
						    
						    // ICI SUIT LE PARSER A MODIFIER
						    
						    String ligneNotes = notes.substring(1, notes.length()-1).replace(",", "").replace("1", "o").replace("0", "-");
						    //System.out.println(":"+symbole.split("-")[0]+" |"+ligneNotes+"|");
						    breakPossibles+=":"+symbole.split("-")[0]+" |"+ligneNotes+"|\n";
						    
						    
						}
						numeroDuBreak++;
					}
				}
				//System.out.println(enTete+breakPossibles+"\n");
				interpreter.stop(myGoal);
				return enTete+breakPossibles;
			} catch (PrologException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}
	}
	
	public static Term miseEnFormeBreak(ArrayList<String> contenu){
		String contenuBreak = "[";
		String separateur = "";
		for(String element : contenu)
		{
			contenuBreak+=separateur+element;
			separateur = ",";
		}
		contenuBreak += "]";
		//System.out.println(contenuBreak);
		try {
			return TermReader.stringToTerm(contenuBreak, env);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}
}	
